/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package memoria_intermedia;

import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * Representa una abstracción de un Gestor de la Memoria Intermedia
 * @author SaHa
 */
public class CGestorMemoriaIntermedia 
{
   /** Representa a los bloques de la memoria intermedia o buffer. */
   private CPaginaBuffer[] buffer;
   /** Numero de paginas en total en el buffer. */
   private int numeroPaginas;
   /** Posición en el buffer de la ultima pagina colocada. */
   private int posicionUltimaPagina = -1;
   /** cola para el control de sustitución basada en LRU. */
   private Queue colaLRU;
   
   public CGestorMemoriaIntermedia(int numeroPaginas)
   {
       this.numeroPaginas=numeroPaginas;
       buffer=new CPaginaBuffer[numeroPaginas];
       colaLRU = new LinkedList<Integer>();
   }
   
   public CPaginaBuffer recuperarPaginaDelBuffer(int numeroPagina) 
   {
       // Verificar si la pagina esta en el buffer
       int posicion = posicionDePaginaEnBuffer(numeroPagina);
       if (posicion >= 0) // la pagina esta en el buffer
       {
           // Marcar Pagina o bloque como recientemente referenciado
           colaLRU.remove(numeroPagina);
           colaLRU.add(numeroPagina);
           // devolver la pagina del buffer al solicitante
           return buffer[posicion];
       }
       return null;
   }      
   
   public CPaginaBuffer ponerPaginaEnBuffer(CPaginaBuffer pagina) 
   {
       // Si la pagina esta en el buffer
       if (estaPaginaEnBuffer(pagina)) 
       {
           // no descartar ninguna pagina o bloque
           return null;
       } // Si la pagina no esta en el buffer, pero con espacio en el buffer
       else
       {
           if (!bufferLLeno()) 
           {
               // Asignar la nueva pagina al bloque o pagina libre del buffer
               posicionUltimaPagina++;
               buffer[posicionUltimaPagina] = pagina;
               // Actualizar la LRU
               colaLRU.remove(posicionUltimaPagina);
               colaLRU.add(posicionUltimaPagina);
               return null;
           } // Si la pagina no esta en el buffer, pero sin espacio en el buffer
           else 
           {
               // recuperar la pagina a descartar
               //
               int numeroPaginaDescartada = (Integer) colaLRU.remove();
               int posicion = posicionDePaginaEnBuffer(numeroPaginaDescartada);
               //extraer la pagina y descartar del buffer
               CPaginaBuffer paginaDescartada = buffer[posicion];
               //actualizar la nueva pagina en la posicion de la pagina descartada
               buffer[posicion] = pagina;
               //tengo que hacer que el id de la pagina sea el mas recientemente utilizado
               colaLRU.add(pagina.getNumeroPagina());
               
               return paginaDescartada;
           }
       }
   }
   
   private int posicionDePaginaEnBuffer(int numeroPagina) 
   {
       int posicion = -1;
       for (int i = 0; i < buffer.length; i++) 
       {
           if ((buffer[i] != null) && (numeroPagina == buffer[i].getNumeroPagina())) 
           {
               posicion = i;
               break;
           }
       }
       return posicion;
   }
   
   private boolean estaPaginaEnBuffer(CPaginaBuffer pagina) 
   {
       return (posicionDePaginaEnBuffer(pagina.getNumeroPagina()) != -1);
   }
   
   private boolean bufferLLeno() 
   {
       return numeroPaginas - 1 == posicionUltimaPagina;
   }

   @Override
   public String toString() 
   {
       String resultado = "";
       for (int i = 0; i < buffer.length; i++) 
       {
           resultado += "Pagina[" + i + "]: " + buffer[i] + "\n";
       }
       return resultado + "\n" + this.colaLRU;
   }
   
   public static void main(String[] args) 
   {
       // Crear un gestor de memoria
       CGestorMemoriaIntermedia gestorBuffer = new CGestorMemoriaIntermedia(6);
       // Paginas del Disco
       System.out.println("Paginas del Disco: ");
       CPaginaBuffer[] paginas = new CPaginaBuffer[10];
       for (int i = 0; i < paginas.length; i++) 
       {
           CPaginaBuffer pagina = new CPaginaBuffer(i, "p" + i);
           paginas[i] = pagina;
           System.out.println(pagina);
       }

       System.out.println("Contenido del Gestor: ");
       System.out.println(gestorBuffer);


       for (int i = 0; i < paginas.length; i++) 
       {
           gestorBuffer.ponerPaginaEnBuffer(paginas[i]);
       }

       System.out.println("Contenido del Gestor despues de poner bloques: ");
       System.out.println(gestorBuffer);

       System.out.println("Poner una página al Buffer: ");
       CPaginaBuffer paginaN = new CPaginaBuffer(10,"p10");
       CPaginaBuffer paginaE = gestorBuffer.ponerPaginaEnBuffer(paginaN);
       System.out.println(paginaE);
       System.out.println(gestorBuffer);
                     
       System.out.println("Recuperar una Pagina del Buffer: ");
       CPaginaBuffer pagina1 = gestorBuffer.recuperarPaginaDelBuffer(7);
       System.out.println(pagina1);
       System.out.println(gestorBuffer);

       System.out.println("Recuperar otra Pagina del Buffer: ");
       CPaginaBuffer pagina2 = gestorBuffer.recuperarPaginaDelBuffer(1);
       System.out.println(pagina2);
       System.out.println(gestorBuffer);
   }
}
